package shining365.programmableweb.data.app;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.Map.Entry;

import javax.xml.bind.JAXBException;

import org.junit.Test;

import shining365.programmableweb.data.common.Utils;
import shining365.programmableweb.data.history.Api;
import shining365.programmableweb.data.history.History;
import shining365.programmableweb.data.history.History.TimePoint;

public class HistoryOfApiCentrality {
	
	@Test
	public void computeCentralityHistory() throws IOException, ParseException, JAXBException {
		History history = null;
		try {
			history = 
				Utils.unmarshallFromFile(History.class, HISTORY_FILE);
		} catch (Exception e) {}
		
		final int step = 7;
		Calendar calendar = 
			new GregorianCalendar(2005, Calendar.SEPTEMBER, 18, 0, 0, 0);
		calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
		
		if (history == null) {
			history = new History();
		} else {
			List<TimePoint> timePointList = history.getTimePoint();
			Date lastDate = 
				timePointList.get(timePointList.size() - 1).getDateItem();
			calendar.setTimeInMillis(lastDate.getTime());
			calendar.add(Calendar.DAY_OF_MONTH, step);
		}
		
		Date endDate = new SimpleDateFormat("yyyy-MM-dd").parse("2009-09-21");
		while (true) {
			Date date = calendar.getTime();
			if (date.compareTo(endDate) > 0) {
				break;
			}
			
			ApiCentrality ac = new ApiCentrality(date);
			Map<String, Double> api2centrality = ac.getApiCentralities();
			
			TimePoint timePoint = new TimePoint();
			timePoint.setDateItem(date);
			timePoint.setAverageCentrality(api2centrality.get("AVERAGE"));
			api2centrality.remove("AVERAGE");
			for (Entry<String, Double> entry : api2centrality.entrySet()) {
				Api api = new Api();
				api.setUrl(entry.getKey());
				api.setCentrality(entry.getValue());
				timePoint.getApi().add(api);
			}
			history.getTimePoint().add(timePoint);
			Utils.marshallToFile(history, HISTORY_FILE);
			
			calendar.add(Calendar.DAY_OF_MONTH, step);
		}
	}
	
	@Test
	public void readCentralityHistory() throws JAXBException, IOException {
		History centralityHistory = 
			Utils.unmarshallFromFile(History.class, HISTORY_FILE);
		
		Map<String, List<Double>> api2centralities = 
			new HashMap<String, List<Double>>();
		api2centralities.put("AVERAGE", new ArrayList<Double>());
		for (TimePoint timePoint : centralityHistory.getTimePoint()) {
			api2centralities.get("AVERAGE").add(timePoint.getAverageCentrality());
			for (Api api : timePoint.getApi()) {
				List<Double> centralities = api2centralities.get(api.getUrl());
				if (centralities == null) {
					centralities = new ArrayList<Double>();
				}
				centralities.add(api.getCentrality());
				api2centralities.put(api.getUrl(), centralities);
			}
		}
		
		for (Entry<String, List<Double>> entry : api2centralities.entrySet()) {
			System.out.println(entry.getKey());
			List<Double> centralities = entry.getValue();
			int week = LATEST_WEEK - centralities.size();
			for (double d : centralities) {
				System.out.printf("%d\t%f\n", ++week, d);
			}
			System.out.println();
		}
	}
	
	@Test
	public void readCentralityHistoryRanks() throws JAXBException, IOException {
		History centralityHistory = 
			Utils.unmarshallFromFile(History.class, HISTORY_FILE);
		
		Map<String, List<Integer>> api2ranks = 
			new HashMap<String, List<Integer>>();
		for (TimePoint timePoint : centralityHistory.getTimePoint()) {
			Collections.sort(timePoint.getApi(), new Comparator<Api>(){
				@Override
				public int compare(Api o1, Api o2) {
					return Double.compare(o2.getCentrality(), o1.getCentrality());
				}
			});
			int rank = 1;
			for (Api api : timePoint.getApi()) {
				List<Integer> ranks = api2ranks.get(api.getUrl());
				if (ranks == null) {
					ranks = new ArrayList<Integer>();
				}
				ranks.add(rank++);
				api2ranks.put(api.getUrl(), ranks);
			}
		}
		
		for (Entry<String, List<Integer>> entry : api2ranks.entrySet()) {
			System.out.println(entry.getKey());
			List<Integer> ranks = entry.getValue();
			int week = LATEST_WEEK - ranks.size();
			for (int r : ranks) {
				System.out.printf("%d\t%d\n", ++week, r);
			}
			System.out.println();
		}
	}
	
	@Test
	public void readCentralityHistoryTop10Avg() throws JAXBException, IOException {
		History centralityHistory = 
			Utils.unmarshallFromFile(History.class, HISTORY_FILE);
		
		List<Double> avgs = new ArrayList<Double>();
		final int N = 10;
		for (TimePoint timePoint : centralityHistory.getTimePoint()) {
			Collections.sort(timePoint.getApi(), new Comparator<Api>(){
				@Override
				public int compare(Api o1, Api o2) {
					return Double.compare(o2.getCentrality(), o1.getCentrality());
				}
			});
			
			double sum = 0;
			for (int i = 0; i < N; i++) {
				sum += timePoint.getApi().get(i).getCentrality();
			}
			avgs.add(sum / N);
		}
		
		for (double avg : avgs) {
			System.out.println(avg);
		}
	}
	
	private final static String HISTORY_FILE = "doc/centrality.history.xml";
	private static final int LATEST_WEEK = 210;
}
